﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;

namespace DigitalImage.softLib {
    class CDictionary {
        protected List<SortedSet<char>> smallPricePairs;
        public List<string> wordDictionary;
        protected StreamReader inputFile;

        public string FilePath {
            get;
            set;
        }

        public double SmallPrice {
            get;
            set;
        }

        public string WordPattern {
            get;
            set;
        }

        public bool CaseSensitive {
            get;
            set;
        }

        public CDictionary(string filePath,string wordPattern) {
            CaseSensitive=false;
            smallPricePairs=new List<SortedSet<char>>();
            wordDictionary=new List<string>();

            FilePath=filePath;
            inputFile=new StreamReader(FilePath,Encoding.UTF8);
            
            SmallPrice=0;
            WordPattern=wordPattern;

            initializeDictionary();
        }

        protected void initializeDictionary() {
            string newRow;
            Regex regex=new Regex(WordPattern);
            
            while(inputFile.Peek()!=-1){
                newRow=inputFile.ReadLine();
                if(!CaseSensitive) {
                    newRow=newRow.ToLower();
                }
                MatchCollection matches=regex.Matches(newRow);
                foreach(Match match in matches) {
                    if(!wordDictionary.Contains(match.Value)) {
                        wordDictionary.Add(match.Value);
                    }
                }
            }
        }

        public void addSmallPricePair(char c1,char c2){
            bool contains=false;
            foreach(SortedSet<char> set in smallPricePairs){
                if(set.Contains(c1)||set.Contains(c2)) {
                    contains=true;
                    set.Add(c1);
                    set.Add(c2);
                    break;
                }
            }
            if(!contains) {
                SortedSet<char> set=new SortedSet<char>();
                set.Add(c1);
                set.Add(c2);
                smallPricePairs.Add(set);
            }
        }

        protected bool isSmallPricePair(char c1, char c2) {
            bool contains=false;
            foreach(SortedSet<char> set in smallPricePairs) {
                if(set.Contains(c1)&&set.Contains(c2)) {
                    contains=true;
                    break;
                }
            }
            return contains;
        }

        public string findNearesWord(string word) {
            string result="";
            double bestResult=Double.MaxValue;
            double currentResult;
            if(!CaseSensitive) {
                word=word.ToLower();
            }
            foreach(string dictWord in wordDictionary) {
                currentResult=levenshteinDistance(word, dictWord);
                if(currentResult<bestResult) {
                    bestResult=currentResult;
                    result=dictWord;
                }
            }
            return result;
        }

        protected double levenshteinDistance(string source, string target){
            int m = source.Length;
            int n = target.Length;

            // inicijalizacija matrice
            double[,] d = new double[m + 1, n + 1];
            // prvo popuni celu matricu nulama
            for (int i = 0; i < m + 1; i++)
            {
                for (int j = 0; j < n + 1; j++)
                {
                    d[i, j] = 0;
                }

            }

            // inicijalizacija prve kolone
            // source moze biti transformisan u prazan string izbacivanjem svih karaktera iz source
            for (int i = 1; i <= m; i++)
            {
                d[i, 0] = i;
            }

            // inicijalizacija prvog reda
            // do targeta se moze doci od praznog stringa ubacivanjem svih karaktera iz target
            for (int j = 1; j <= n; j++)
            {
                d[0, j] = j;
            }

            for (int j = 1; j <= n; j++)
            {
                for (int i = 1; i <= m; i++)
                {
                    if (source[i - 1] == target[j - 1])
                    {
                        d[i, j] = d[i - 1, j - 1];
                    }
                    else
                    {
                        double price;
                        if(isSmallPricePair(source[i-1], target[j-1])) {
                            price=SmallPrice;
                        } else {
                            price=1;
                        }

                        d[i, j]=Math.Min(Math.Min(d[i-1, j]+price+0.1, // deletion
                                            d[i, j-1]+price+0.1), // insertion
                                            d[i-1, j-1]+price); // substitution
                        
                    }
                }
            }
            return d[m, n];
        }
    
        
    }
}
